<?php
namespace Matrix;

/**
 * 配置类
 *
 * 帮助管理应用和包的配置文件
 *
 * 注册配置文件导入:
 * <code>
 * Event::listen(Config::loader, function ($bundle, $file) {
 *		return Config::file($bundle, $file);
 * });
 * </code>
 *
 * 获取配置文件:
 * <code>
 * // 读取application/confing/application.php文件数组的aliases数组单元
 * Config::get('application.aliases');
 *
 * // 将读取Bundle::path(admin).'config/application.php'文件数组的aliases数组单元
 * Config::get('admin::application.aliases');
 * </code>
 *
 * 临时更改或添加一个配置项:
 * <code>
 * Config::set('application', array());
 * Config::set('admin::application.ip.address', '127.0.0.1');
 * </code>
 *
 * 判断配置项是否存在:
 * <code>
 * Config::has('application');
 * </code>
 *
 * 临时删除一个配置项
 * <code>
 * Config::delete('application.index_page');
 * </code>
 */
class Config
{
	/**
	 * 配置导入事件名
	 *
	 * @var array
	 */
	const loader = 'matrix.config.loader';
	
	/**
	 * 所有导入配置项
	 *
	 * @var array
	 */
	public static $items = array();
	
	/**
	 * 解释配置项的缓存
	 *
	 * @var array
	 */
	public static $cache = array();
	
	/**
	 * 检测配置项是否存在
	 *
	 * @param	string	$key
	 * @return	boolean
	 */
	public static function has($key)
	{
		return static::get($key) !== null;
	}
	
	/**
	 * 获取配置项或者整个配置文件数组
	 *
	 * @param	string	$key
	 * @param	mixed	$default
	 * @return	mixed
	 */
	public static function get($key, $default = null)
	{
		list($bundle, $file, $item) = static::parse($key);
		if (!static::load($bundle, $file)) {
			return value($default);
		}
		$items = static::$items[$bundle][$file];
		if ($item === null) {
			return $items;
		}
		return array_get($items, $item, $default);
	}
	
	/**
	 * 设置一个配置项或者一个配置文件数组
	 *
	 * @param	string	$key
	 * @param	mixed	$value
	 * @return	void
	 */
	public static function set($key, $value)
	{
		list($bundle, $file, $item) = static::parse($key);
		static::load($bundle, $file);
		if ($item === null) {
			array_set(static::$items[$bundle], $file, $value);
		} else {
			array_set(static::$items[$bundle][$file], $item, $value);
		}
	}
	
	/**
	 * 临时删除配置项或者一个配置文件数组
	 *
	 * @param	string	$key
	 * @return	void
	 */
	public static function delete($key)
	{
		list($bundle, $file, $item) = static::parse($key);
		static::load($bundle, $file);
		if ($item === null) {
			// 无用, 再次获取时候, 仍然会加载进来
			//array_delete(static::$items[$bundle], $file);
		} else {
			array_delete(static::$items[$bundle][$file], $item);
		}
	}
	
	/**
	 * 导入指定配置文件, 返回配置文件是否已经导入
	 *
	 * @param	string	$bundle
	 * @param	string	$file
	 * @return	void
	 */
	public static function load($bundle, $file)
	{
		if (isset(static::$items[$bundle][$file])) {
			return true;
		}
		$config = Event::first(static::loader, func_get_args());
		if (!empty($config)) {
			static::$items[$bundle][$file] = $config;
		}
		return isset(static::$items[$bundle][$file]);
	}
	
	/**
	 * 导入指定配置文件, 返回配置文件数组
	 *
	 * @param	string	$bundle
	 * @param	string	$file
	 * @return	array
	 */
	public static function file($bundle, $file)
	{
		$config = array();
		foreach (static::paths($bundle) as $directory) {
			if (file_exists($path = $directory.$file.EXT)) {
				$config = array_merge($config, include $path);
			}
		}
		return $config;
	}
	
	/**
	 * 解析键为一个数组
	 *
	 * @param	string	$key
	 * @return	array
	 */
	protected static function parse($key)
	{
		if (isset(static::$cache[$key])) {
			return static::$cache[$key];
		}
		$bundle = Bundle::name($key);
		$segments = explode('.', Bundle::element($key));
		if (count($segments) >= 2) {
			$parsed = array($bundle, array_shift($segments), implode('.', $segments));
		} else {
			$parsed = array($bundle, $segments[0], null);
		}
		return static::$cache[$key] = $parsed;
	}
	
	/**
	 * 获取包配置文件存在的路径
	 *
	 * @param	string	$bundle
	 * @return	array
	 */
	protected static function paths($bundle)
	{
		$paths[] = Bundle::path($bundle).'config'.DS;
		if (Request::env() !== null) {
			$paths[] = $paths[count($paths) - 1].Request::env().DS;
		}
		return array_diff($paths, array(''));
	}
	
}